using System;
using System.Globalization;
using System.Runtime.InteropServices;
using PickGold.Charting;

namespace PickGold.Charting.Formulas
{
	internal class PriceIndicators : IFormula
	{
		private void BollingerBands(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			double num3;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			try
			{
				num3 = double.Parse(parameterList[1], CultureInfo.InvariantCulture);
			}
			catch (Exception)
			{
				throw new InvalidOperationException(SR.ExceptionIndicatorsDeviationMissing);
			}
			bool flag = bool.Parse(extraParameterList[0]);
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			if (inputValues[0].Length < num2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
			}
			outputValues = new double[3][];
			if (flag)
			{
				outputValues[0] = new double[inputValues[0].Length];
				outputValues[1] = new double[inputValues[1].Length];
				outputValues[2] = new double[inputValues[1].Length];
				double[] numArray = new double[inputValues[1].Length];
				this.MovingAverage(inputValues[1], out numArray, num2, true);
				for (int i = 0; i < outputValues[0].Length; i++)
				{
					outputValues[0][i] = inputValues[0][i];
					double num5 = 0.0;
					int num6 = 0;
					if (((i - num2) + 1) > 0)
					{
						num6 = (i - num2) + 1;
					}
					for (int j = num6; j <= i; j++)
					{
						num5 += (inputValues[1][j] - numArray[i]) * (inputValues[1][j] - numArray[i]);
					}
					outputValues[1][i] = numArray[i] + (Math.Sqrt(num5 / ((double)num2)) * num3);
					outputValues[2][i] = numArray[i] - (Math.Sqrt(num5 / ((double)num2)) * num3);
				}
			}
			else
			{
				outputValues[0] = new double[(inputValues[0].Length - num2) + 1];
				outputValues[1] = new double[(inputValues[1].Length - num2) + 1];
				outputValues[2] = new double[(inputValues[1].Length - num2) + 1];
				double[] numArray2 = new double[(inputValues[1].Length - num2) + 1];
				this.MovingAverage(inputValues[1], out numArray2, num2, false);
				for (int k = 0; k < outputValues[0].Length; k++)
				{
					outputValues[0][k] = inputValues[0][(k + num2) - 1];
					double num9 = 0.0;
					for (int m = k; m < (k + num2); m++)
					{
						num9 += (inputValues[1][m] - numArray2[k]) * (inputValues[1][m] - numArray2[k]);
					}
					outputValues[1][k] = numArray2[k] + (Math.Sqrt(num9 / ((double)num2)) * num3);
					outputValues[2][k] = numArray2[k] - (Math.Sqrt(num9 / ((double)num2)) * num3);
				}
			}
		}

		public void CheckNumOfValues(double[][] inputValues, int numOfYValues)
		{
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			for (int i = 1; i < numOfYValues; i++)
			{
				if (inputValues[i].Length != inputValues[i + 1].Length)
				{
					throw new ArgumentException(SR.ExceptionPriceIndicatorsSameYNumber);
				}
			}
		}

		private void Envelopes(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			double num3;
			double[][] numArray;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			try
			{
				num3 = double.Parse(parameterList[1], CultureInfo.InvariantCulture);
			}
			catch (Exception)
			{
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsShiftParameterMissing);
			}
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			this.MovingAverage(inputValues, out numArray, parameterList, extraParameterList);
			outputValues = new double[][] { new double[numArray[0].Length], new double[numArray[0].Length], new double[numArray[0].Length] };
			for (int i = 0; i < numArray[0].Length; i++)
			{
				outputValues[0][i] = numArray[0][i];
				outputValues[1][i] = numArray[1][i] + ((num3 * numArray[1][i]) / 100.0);
				outputValues[2][i] = numArray[1][i] - ((num3 * numArray[1][i]) / 100.0);
			}
		}

		private void ExponentialMovingAverage(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			double num3 = 2.0 / (num2 + 1.0);
			bool flag = bool.Parse(extraParameterList[0]);
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			if (inputValues[0].Length < num2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
			}
			outputValues = new double[2][];
			if (flag)
			{
				outputValues[0] = new double[inputValues[0].Length];
				outputValues[1] = new double[inputValues[1].Length];
				for (int i = 0; i < inputValues[0].Length; i++)
				{
					double num9;
					outputValues[0][i] = inputValues[0][i];
					double num5 = 0.0;
					int num6 = 0;
					if (((i - num2) + 1) > 0)
					{
						num6 = (i - num2) + 1;
					}
					for (int j = num6; j < i; j++)
					{
						num5 += inputValues[1][j];
					}
					int num8 = num2;
					if (num2 > (i + 1))
					{
						num8 = i + 1;
					}
					if (num8 <= 1)
					{
						num9 = 0.0;
					}
					else
					{
						num9 = num5 / ((double)(num8 - 1));
					}
					num3 = 2.0 / (num8 + 1.0);
					outputValues[1][i] = (num9 * (1.0 - num3)) + (inputValues[1][i] * num3);
				}
			}
			else
			{
				outputValues[0] = new double[(inputValues[0].Length - num2) + 1];
				outputValues[1] = new double[(inputValues[1].Length - num2) + 1];
				for (int k = 0; k < outputValues[0].Length; k++)
				{
					double num11;
					outputValues[0][k] = inputValues[0][(k + num2) - 1];
					if (k == 0)
					{
						double num12 = 0.0;
						for (int m = k; m < (k + num2); m++)
						{
							num12 += inputValues[1][m];
						}
						num11 = num12 / ((double)num2);
					}
					else
					{
						num11 = outputValues[1][k - 1];
					}
					outputValues[1][k] = (num11 * (1.0 - num3)) + (inputValues[1][(k + num2) - 1] * num3);
				}
			}
		}

		internal void ExponentialMovingAverage(double[] inputValues, out double[] outputValues, int period, bool startFromFirst)
		{
			double[][] numArray = new double[2][];
			double[][] numArray2 = new double[2][];
			string[] parameterList = new string[1];
			string[] extraParameterList = new string[1];
			parameterList[0] = period.ToString(CultureInfo.InvariantCulture);
			extraParameterList[0] = startFromFirst.ToString(CultureInfo.InvariantCulture);
			numArray[0] = new double[inputValues.Length];
			numArray[1] = inputValues;
			this.ExponentialMovingAverage(numArray, out numArray2, parameterList, extraParameterList);
			outputValues = numArray2[1];
		}

		public virtual void Formula(string formulaName, double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList, out string[][] outLabels)
		{
			string name = formulaName.ToUpper(CultureInfo.InvariantCulture);
			outLabels = null;
			try
			{
				switch (name)
				{
					case "MOVINGAVERAGE":
						this.MovingAverage(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "EXPONENTIALMOVINGAVERAGE":
						this.ExponentialMovingAverage(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "TRIANGULARMOVINGAVERAGE":
						this.TriangularMovingAverage(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "WEIGHTEDMOVINGAVERAGE":
						this.WeightedMovingAverage(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "BOLLINGERBANDS":
						this.BollingerBands(inputValues, out outputValues, parameterList, extraParameterList);
						return;

					case "MEDIANPRICE":
						this.MedianPrice(inputValues, out outputValues);
						return;

					case "TYPICALPRICE":
						this.TypicalPrice(inputValues, out outputValues);
						return;

					case "WEIGHTEDCLOSE":
						this.WeightedClose(inputValues, out outputValues);
						return;

					case "ENVELOPES":
						this.Envelopes(inputValues, out outputValues, parameterList, extraParameterList);
						return;
				}
				outputValues = null;
			}
			catch (IndexOutOfRangeException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaInvalidPeriod(name));
			}
			catch (OverflowException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaNotEnoughDataPoints(name));
			}
		}

		private void MedianPrice(double[][] inputValues, out double[][] outputValues)
		{
			if (inputValues.Length != 3)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
			}
			this.CheckNumOfValues(inputValues, 2);
			outputValues = new double[][] { new double[inputValues[0].Length], new double[inputValues[1].Length] };
			for (int i = 0; i < inputValues[1].Length; i++)
			{
				outputValues[0][i] = inputValues[0][i];
				outputValues[1][i] = (inputValues[1][i] + inputValues[2][i]) / 2.0;
			}
		}

		internal void MovingAverage(double[] inputValues, out double[] outputValues, int period, bool FromFirst)
		{
			double[][] numArray = new double[2][];
			double[][] numArray2 = new double[2][];
			string[] parameterList = new string[1];
			string[] extraParameterList = new string[1];
			parameterList[0] = period.ToString(CultureInfo.InvariantCulture);
			extraParameterList[0] = FromFirst.ToString(CultureInfo.InvariantCulture);
			numArray[0] = new double[inputValues.Length];
			numArray[1] = inputValues;
			this.MovingAverage(numArray, out numArray2, parameterList, extraParameterList);
			outputValues = numArray2[1];
		}

		private void MovingAverage(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			bool flag = bool.Parse(extraParameterList[0]);
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			if (inputValues[0].Length < num2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
			}
			outputValues = new double[2][];
			if (flag)
			{
				outputValues[0] = new double[inputValues[0].Length];
				outputValues[1] = new double[inputValues[1].Length];
				for (int i = 0; i < inputValues[0].Length; i++)
				{
					outputValues[0][i] = inputValues[0][i];
					double num4 = 0.0;
					int num5 = 0;
					if (((i - num2) + 1) > 0)
					{
						num5 = (i - num2) + 1;
					}
					for (int j = num5; j <= i; j++)
					{
						num4 += inputValues[1][j];
					}
					int num7 = num2;
					if (num2 > (i + 1))
					{
						num7 = i + 1;
					}
					outputValues[1][i] = num4 / ((double)num7);
				}
			}
			else
			{
				outputValues[0] = new double[(inputValues[0].Length - num2) + 1];
				outputValues[1] = new double[(inputValues[1].Length - num2) + 1];
				double num8 = 0.0;
				for (int k = 0; k < num2; k++)
				{
					num8 += inputValues[1][k];
				}
				for (int m = 0; m < outputValues[0].Length; m++)
				{
					outputValues[0][m] = inputValues[0][(m + num2) - 1];
					outputValues[1][m] = num8 / ((double)num2);
					if (m < (outputValues[0].Length - 1))
					{
						num8 -= inputValues[1][m];
						num8 += inputValues[1][m + num2];
					}
				}
			}
		}

		internal void StandardDeviation(double[] inputValues, out double[] outputValues, int period, bool startFromFirst)
		{
			double[] numArray;
			if (startFromFirst)
			{
				outputValues = new double[inputValues.Length];
				this.MovingAverage(inputValues, out numArray, period, startFromFirst);
				int index = 0;
				for (int i = 0; i < inputValues.Length; i++)
				{
					double num = 0.0;
					int num4 = 0;
					if (((i - period) + 1) > 0)
					{
						num4 = (i - period) + 1;
					}
					for (int j = num4; j <= i; j++)
					{
						num += (inputValues[j] - numArray[index]) * (inputValues[j] - numArray[index]);
					}
					outputValues[index] = Math.Sqrt(num / ((double)period));
					index++;
				}
			}
			else
			{
				outputValues = new double[(inputValues.Length - period) + 1];
				this.MovingAverage(inputValues, out numArray, period, startFromFirst);
				int num7 = 0;
				for (int k = period - 1; k < inputValues.Length; k++)
				{
					double num6 = 0.0;
					for (int m = (k - period) + 1; m <= k; m++)
					{
						num6 += (inputValues[m] - numArray[num7]) * (inputValues[m] - numArray[num7]);
					}
					outputValues[num7] = Math.Sqrt(num6 / ((double)period));
					num7++;
				}
			}
		}

		private void TriangularMovingAverage(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			double[] numArray;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			bool fromFirst = bool.Parse(extraParameterList[0]);
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			if (inputValues[0].Length < num2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
			}
			outputValues = new double[2][];
			double a = (num2 + 1.0) / 2.0;
			a = Math.Round(a);
			double[] numArray2 = inputValues[1];
			this.MovingAverage(numArray2, out numArray, (int)a, fromFirst);
			this.MovingAverage(numArray, out numArray, (int)a, fromFirst);
			outputValues[1] = numArray;
			outputValues[0] = new double[outputValues[1].Length];
			if (fromFirst)
			{
				outputValues[0] = inputValues[0];
			}
			else
			{
				for (int i = 0; i < outputValues[1].Length; i++)
				{
					outputValues[0][i] = inputValues[0][((((int)a) - 1) * 2) + i];
				}
			}
		}

		private void TypicalPrice(double[][] inputValues, out double[][] outputValues)
		{
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			this.CheckNumOfValues(inputValues, 3);
			outputValues = new double[][] { new double[inputValues[0].Length], new double[inputValues[1].Length] };
			for (int i = 0; i < inputValues[1].Length; i++)
			{
				outputValues[0][i] = inputValues[0][i];
				outputValues[1][i] = ((inputValues[1][i] + inputValues[2][i]) + inputValues[3][i]) / 3.0;
			}
		}

		private void WeightedClose(double[][] inputValues, out double[][] outputValues)
		{
			if (inputValues.Length != 4)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
			}
			this.CheckNumOfValues(inputValues, 3);
			outputValues = new double[][] { new double[inputValues[0].Length], new double[inputValues[1].Length] };
			for (int i = 0; i < inputValues[1].Length; i++)
			{
				outputValues[0][i] = inputValues[0][i];
				outputValues[1][i] = ((inputValues[1][i] + inputValues[2][i]) + (inputValues[3][i] * 2.0)) / 4.0;
			}
		}

		private void WeightedMovingAverage(double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList)
		{
			int num2;
			int length = inputValues.Length;
			try
			{
				num2 = int.Parse(parameterList[0], CultureInfo.InvariantCulture);
			}
			catch (Exception exception)
			{
				if (exception.Message == SR.ExceptionObjectReferenceIsNull)
				{
					throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
				}
				throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + exception.Message);
			}
			if (num2 <= 0)
			{
				throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
			}
			bool flag = bool.Parse(extraParameterList[0]);
			if (length != 2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
			}
			if (inputValues[0].Length != inputValues[1].Length)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
			}
			if (inputValues[0].Length < num2)
			{
				throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
			}
			outputValues = new double[2][];
			if (flag)
			{
				outputValues[0] = new double[inputValues[0].Length];
				outputValues[1] = new double[inputValues[1].Length];
				for (int i = 0; i < inputValues[0].Length; i++)
				{
					double num9;
					outputValues[0][i] = inputValues[0][i];
					double num4 = 0.0;
					int num5 = 0;
					if (((i - num2) + 1) > 0)
					{
						num5 = (i - num2) + 1;
					}
					int num6 = 1;
					int num7 = 0;
					for (int j = num5; j <= i; j++)
					{
						num4 += inputValues[1][j] * num6;
						num7 += num6;
						num6++;
					}
					if (i == 0)
					{
						num9 = inputValues[1][0];
					}
					else
					{
						num9 = num4 / ((double)num7);
					}
					outputValues[1][i] = num9;
				}
			}
			else
			{
				outputValues[0] = new double[(inputValues[0].Length - num2) + 1];
				outputValues[1] = new double[(inputValues[1].Length - num2) + 1];
				for (int k = 0; k < outputValues[0].Length; k++)
				{
					outputValues[0][k] = inputValues[0][(k + num2) - 1];
					double num11 = 0.0;
					int num12 = 1;
					int num13 = 0;
					for (int m = k; m < (k + num2); m++)
					{
						num11 += inputValues[1][m] * num12;
						num13 += num12;
						num12++;
					}
					double num15 = num11 / ((double)num13);
					outputValues[1][k] = num15;
				}
			}
		}

		public virtual string Name
		{
			get
			{
				return SR.FormulaNamePriceIndicators;
			}
		}
	}
}

